#include "stdafx.h"
#include "Node.h"
#include "Util.h"
using namespace std;

extern Bus myBus;
extern ofstream log;

Node::Node()
{	
	mOutboundFrame = NULL;
	mInboundFrame = NULL;
	mStatus = Listening;

	mBitIndex = 0;
	mLastSentBit = true;
	mIdenticalValue = true;
	mConsecutiveCount = 0;
}

Node::~Node()
{
}

void Node::prepareSending()
{
	log << "Node prepares to send frame." << endl;
	mStatus = Sending;
	log << "Node is in status - Sending." << endl;
	mBitIndex = 0;
	mIdenticalValue = true;
	mConsecutiveCount = 0;
}

void Node::finishSending()
{
	log << "Node finishes sending frame." << endl;
	mStatus = Listening;
	log << "Node is in status - Listening." << endl;
	mBitIndex = 0;
	mIdenticalValue = true;
	mConsecutiveCount = 0;
	mOutboundFrame = NULL;//todo
}

void Node::cancelSending()
{
	log << "Node cancels sending frame." << endl;
	mStatus = Listening;
	log << "Node is in status - Listening." << endl;
	mBitIndex = 0;
	mIdenticalValue = true;
	mConsecutiveCount = 0;
}

void Node::prepareReceiving()
{
	log << "Node prepares to receive frame." << endl;
	mStatus = Receiving;
	log << "Node is in status - Receiving." << endl;
	mBitIndex = 0;
	mIdenticalValue = true;
	mConsecutiveCount = 0;
}

void Node::sendOneBit()
{
	log << "Node sends out one bit." << endl;
	bool bit_to_send = mOutboundFrame->getBit(mBitIndex);
	myBus.trySetCurBit(bit_to_send);
	mLastSentBit = bit_to_send;
	mBitIndex++;
}

void Node::sendStuffBit()
{
	bool bit_to_send = !mIdenticalValue;
	log << "Node sends out one stuff bit." << endl;
	myBus.trySetCurBit(bit_to_send);
	mConsecutiveCount = 0;
	mLastSentBit = bit_to_send;
}

bool Node::isLastBitSentOut()
{
	bool bus_prv_bit = myBus.getPrvBit();
	return EQ(bus_prv_bit,mLastSentBit);
}

void Node::run()
{
	bool bit_to_send = true;

	switch(mStatus)
	{
	case Listening:
		if((myBus.getCurStatus()==Idle) && (mOutboundFrame != NULL))
		{
			prepareSending();
			mIdenticalValue = mOutboundFrame->getBit(mBitIndex);
			mConsecutiveCount = 1;
			sendOneBit();
		}
		break;
	case Sending:
		if(mConsecutiveCount==5)
		{
			sendStuffBit();
			break;
		}
		//if there are still bits left to be sent
		if(mBitIndex <= mOutboundFrame->getLength()-1)
		{
			bit_to_send = mOutboundFrame->getBit(mBitIndex);
			//if Stuffing needs to be considered
			if(mBitIndex <= mOutboundFrame->getLength()-1-ACK-EoF)
			{
				if((mConsecutiveCount==0) || (NE(bit_to_send,mIdenticalValue)))
				{
					mIdenticalValue = bit_to_send;
					mConsecutiveCount=1;
				}
				else
				{
					mConsecutiveCount++;
				}
			}
			//if last bit was sent successfully
			if(isLastBitSentOut())
			{
				sendOneBit();
			}
			else //if last bit was not sent successfully
			{
				if(mBitIndex-1<=11) //if the failed last bit is part of ID
				{
					cancelSending();
				}
				else if(mBitIndex-1==12) //if the failed last bit is RTR
				{
					prepareReceiving();
				}
				else
				{
					//throw exception here
					log << "========Exception: Last bit was not sent successfully." << endl;
				}
				break;
			}
		}
		else //if all bits of mOutboundFrame were sent, reset node to listening status
		{
			finishSending();
		}
		break;
	case Receiving: 
		log << "Node is in status - Receiving." << endl;
		break;
	default: break;
	}
	
}

Frame* Node::getOutboundFrame()
{
	return mOutboundFrame;
}

void Node::setOutboundFrame(Frame* outboundFrame)
{
	mOutboundFrame = outboundFrame;
}

Frame* Node::getInboundFrame()
{
	return mInboundFrame;
}

void Node::setInboundFrame(Frame* inboundFrame)
{
	mInboundFrame = inboundFrame;
}

void Node::sendNextBit(int index)
{
	//switch(mConsecutiveCount)
	//{
	//case 0: //if mConsecutiveCount is initialized to 0
	//	mIdenticalValue = bit_to_send;
	//	mConsecutiveCount=1;
	//	break;
	//case 5:
	//	log << "Node sends one STUFF bit." << endl;
	//	myBus.trySetCurBit(!bit_to_send);
	//	mConsecutiveCount=0;
	//	return;
	//	//break;
	//default:
	//	break;
	//}

	if(index < mOutboundFrame->getLength()-1) //if there are still bits left to be sent
	{
		bool bit_to_send = mOutboundFrame->getBit(index);
		FrameType frame_type = mOutboundFrame->getFrameType();
		//if it is a data/remote frame, and bit_to_send is inside SoF, ARB, CON, DAT, CRC
		//then Bit Stuffing is needed
		if((frame_type==Data || frame_type==Remote) && (index <= mOutboundFrame->getLength()-1-EoF-ACK))
		{
			
			if(mConsecutiveCount==0) //if mConsecutiveCount is initialized to 0
			{
				mIdenticalValue = bit_to_send;
				mConsecutiveCount=1;
			}
			else
			{
				if(!bit_to_send==!mIdenticalValue) //if another bit of identical value is detected
				{
					if(mConsecutiveCount==5) //if 5 consecutive bits of identical value have already been detected
					{
						log << "Node sends one STUFF bit." << endl;
						myBus.trySetCurBit(!bit_to_send);
						mConsecutiveCount=0;
						return;
					}
					else
					{
						mConsecutiveCount++;
					}
				}
				else //if different value is detected
				{
					mIdenticalValue = bit_to_send;
					mConsecutiveCount=1;
				}
			}


		}
		log << "Node sends one bit." << endl;
		myBus.trySetCurBit(bit_to_send);
		mBitIndex++;
	}
	else //if all bits of mOutboundFrame were sent, reset node to dequeening status
	{
		log << "Node has no more bit to send." << endl;
		mOutboundFrame = NULL;
		mStatus = Listening;
		mBitIndex = 0;
		mConsecutiveCount = 0;
	}
}



//bool Node::validateFrame()
//{
//	return true;
//}